package org.example.annotation;

import org.example.factory.BeanFactory;
import org.example.factory.ProxyFactory;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;

import static org.example.annotation.AnnoUtil.getReferenceList;

public class MyContext {

    //IOC容器，bean何id的形式保存
    private static HashMap<String, Object> beanMap = new HashMap<String, Object>();
    //IOD容器的class何ID对应关系
    private static HashMap<Class<?>, String> beanClassToId = new HashMap<Class<?>, String>();


    //根据ID获取IOC容器中的bean
    public static Object getBean(String id) {
        if (beanMap.containsKey(id)) {
            return beanMap.get(id);
        } else {
            System.out.println(id + " : 的bean不存在");
        }
        return null;
    }

    //根据class获取IOC容器中的bean
    public static Object getBean(Class<?> c) {
        return beanMap.get(beanClassToId.get(c));
    }

    //向IOC容器中添加bean
    public static void setBean(String id, Object o) {
        id = id.substring(0, 1).toLowerCase() + id.substring(1);
        beanMap.put(id, o);
        Class<?>[] interfaces = o.getClass().getInterfaces();
        if (interfaces == null || interfaces.length == 0) {
            beanClassToId.put(o.getClass(), id);
        } else {
            beanClassToId.put(interfaces[0], id);
        }
    }

    public static void printMap() {
        for (String id : beanMap.keySet()) {
            System.out.println(id + "  ==  " + beanMap.get(id));
        }
    }


    private String base_package = "org.example";
    private Class<?> configClass;

    public MyContext(Class<?> configClass) throws Exception {
        this.configClass = configClass;
        init();
    }

    public void init() throws Exception {

        //获取注解指定扫描包下所有类的全限定类名的集合
        HashSet<String> classNameList = getReferenceList(configClass, base_package);

        //添加到IOC容器中
        for (String s : classNameList) {
            Class<?> aClass = Class.forName(s);
            execIServiceAndIComponent(aClass);
        }

        //给IOC容器中的bean自动注入
        for (String id : beanMap.keySet()) {
            Object o = beanMap.get(id);
            execIAutowired(o);
        }

        //事务管理
        ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
        for (String id : beanMap.keySet()) {

            execITransactional(id, proxyFactory);

        }

    }


    public void execIServiceAndIComponent(Class<?> aClass) throws Exception {
        boolean isIService = aClass.isAnnotationPresent(IService.class);
        boolean isIComponent = aClass.isAnnotationPresent(IComponent.class);
        Object instance = null;
        String id = null;

        if (isIService) {
            IService iService = aClass.getAnnotation(IService.class);
            id = iService.value();
            if ("".equals(id)) {
                id = aClass.getSimpleName();
            }
        } else if (isIComponent) {
            IComponent iComponent = aClass.getAnnotation(IComponent.class);
            id = iComponent.value();
            if ("".equals(id)) {
                id = aClass.getSimpleName();
            }
        }
        if (isIService || isIComponent) {
            instance = aClass.newInstance();
            setBean(id, instance);
        }
    }

    public void execIAutowired(Object obj) throws Exception {
        Class<?> aClass = obj.getClass();
        Field[] fields = aClass.getDeclaredFields();
        for (Field f : fields) {
            if (f.isAnnotationPresent(IAutowired.class)) {
                IAutowired iAutowired = f.getAnnotation(IAutowired.class);
                String name = f.getName();
                String id = iAutowired.value();
                Object bean = null;

                if (!"".equals(id)) {
                    bean = getBean(id);

                } else {
                    Class<?> type = f.getType();
                    bean = getBean(type);
                }

                f.setAccessible(true);
                f.set(obj, bean);
            }
        }
    }

    public void execITransactional(String id, ProxyFactory proxyFactory) {
        Object obj = getBean(id);
        Class<?> aClass = obj.getClass();
        boolean b = aClass.isAnnotationPresent(ITransactional.class);
        if (b) {
            Object cglibProxy = proxyFactory.getCglibProxy(obj);
            setBean(id, cglibProxy);
        }
    }


}
